package com.rlyy.basic.resolver.valid.check;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;
import javax.validation.groups.Default;
import java.util.Set;
import java.util.StringJoiner;

/**
 * 参数校验器工厂
 *
 * @author yuanqinglong
 * @since 2021/2/26 17:31
 */
@Component
public class ValidatorFactoryUtils {

    /**
     * 快速失败校验器，有一个校验未通过直接返回错误 不在继续校验
     */
    @Autowired
    private ValidatorFailFastFactory validatorFailFast;

    /**
     * 返回全部的校验未通过错误提示
     */
    @Autowired
    private ValidatorFactory localValidatorFactoryBean;


    /**
     * 错误信息的分隔符
     */
    private static final String DELIMITER = ";";

    public Validator getValidatorFailFast() {
        return validatorFailFast.getValidator();
    }


    public Validator getValidator() {
        return localValidatorFactoryBean.getValidator();
    }


    /**
     * 快速失败校验，获取校验方法单个参数的校验器
     *
     * @return 参数校验器
     */
    private ExecutableValidator getExecutableFastFailValidator() {
        return getValidatorFailFast().forExecutables();
    }


    /**
     * 获取校验方法单个参数的校验器
     *
     * @return 参数校验器
     */
    private ExecutableValidator getExecutableValidator() {
        return getValidator().forExecutables();
    }


    /**
     * 获取校验方法单个参数的校验器
     *
     * @param fastFail true 启用快速失败校验、false 校验全部
     * @return 参数校验器
     */
    public ExecutableValidator getExecutableValidator(boolean fastFail) {
        return fastFail ? getExecutableFastFailValidator() : getExecutableValidator();
    }


    /**
     * 快速失败校验，有一个校验未通过直接返回错误
     *
     * @param o     参数
     * @param group 组
     * @return 错误信息
     */
    private String fastFailValidator(Object o, Class<?>... group) {
        Set<ConstraintViolation<Object>> validate = getValidatorFailFast().validate(o, group);
        for (ConstraintViolation<Object> tConstraintViolation : validate) {
            return tConstraintViolation.getMessage();
        }
        return null;
    }

    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o     参数
     * @param group 组
     * @return 错误信息
     */
    public String validator(Object o, Class<?>... group) {
        Set<ConstraintViolation<Object>> validate = getValidator().validate(o, group);
        return validResult2String(validate);
    }


    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o        参数
     * @param fastFail true 启用快速失败校验、false 校验全部
     * @param group    组
     * @return 错误信息
     */
    public String validator(Object o, boolean fastFail, Class<?>... group) {
        return fastFail ? fastFailValidator(o, group) : validator(o, group);
    }


    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o 参数
     * @return 错误信息
     */
    public String fastFailValidator(Object o) {
        return fastFailValidator(o, Default.class);
    }


    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o 参数
     * @return 错误信息
     */
    public String validator(Object o) {
        return validator(o, Default.class);
    }

    /**
     * 转换集合为错误信息
     *
     * @param result 错误集合
     */
    public static String validResult2String(Set<ConstraintViolation<Object>> result) {
        if (CollectionUtils.isEmpty(result)) {
            return null;
        }

        StringJoiner stringJoiner = new StringJoiner(DELIMITER);
        for (ConstraintViolation<Object> tConstraintViolation : result) {
            stringJoiner.add(tConstraintViolation.getMessage());
        }
        return stringJoiner.toString();
    }


}
